package com.lsh.oms.core.redis;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;

import java.lang.reflect.Method;

/**
 *
 * @author huangdong
 * @date 16/8/28
 */
public class RedisProxyHandler implements MethodInterceptor {

    private final JedisPool jedisPool;

    private final ShardedJedisPool shardedJedisPool;

    public static Jedis newProxy(JedisPool jedisPool) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Jedis.class);
        enhancer.setCallback(new RedisProxyHandler(jedisPool));
        return (Jedis) enhancer.create();
    }

    public static Jedis newProxy(ShardedJedisPool shardedJedisPool) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Jedis.class);
        enhancer.setCallback(new RedisProxyHandler(shardedJedisPool));
        return (Jedis) enhancer.create();
    }

    private RedisProxyHandler(JedisPool jedisPool) {
        this(jedisPool, null);
    }

    private RedisProxyHandler(ShardedJedisPool shardedJedisPool) {
        this(null, shardedJedisPool);
    }

    private RedisProxyHandler(JedisPool jedisPool, ShardedJedisPool shardedJedisPool) {
        this.jedisPool = jedisPool;
        this.shardedJedisPool = shardedJedisPool;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        if (args == null) {
            throw new NullPointerException("arguments is null!");
        }
        if (args.length <= 0) {
            throw new IllegalArgumentException("arguments is empty!");
        }
        Object key = args[0];
        if (key == null) {
            throw new NullPointerException("first argument is null!");
        }
        if (!(key instanceof String || key instanceof byte[])) {
            throw new IllegalArgumentException("first argument'type must be String or byte[]");
        }
        if (this.jedisPool != null) {
            Jedis jedis = null;
            try {
                jedis = this.jedisPool.getResource();
                return method.invoke(jedis, args);
            } finally {
                if (jedis != null) {
                    jedis.close();
                }
            }
        } else if (this.shardedJedisPool != null) {
            ShardedJedis jedis = null;
            try {
                jedis = this.shardedJedisPool.getResource();
                if (key instanceof String) {
                    return method.invoke(jedis.getShard((String) key), args);
                } else {
                    return method.invoke(jedis.getShard((byte[]) key), args);
                }
            } finally {
                if (jedis != null) {
                    jedis.close();
                }
            }
        } else {
            throw new NullPointerException("jedis pool is null!");
        }
    }
}